package com.sinosun.autotestmachine.tools;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.sinosun.autotestmachine.App;
import com.sinosun.autotestmachine.Element;
import com.sinosun.autotestmachine.tools.Excutor.CaseScheduler;
import com.sinosun.autotestmachine.tools.parser.CaseInformation;
import com.sinosun.autotestmachine.tools.parser.ParamKey;
import com.sinosun.autotestmachine.tools.reader.InformationReader;
import com.sinosun.autotestmachine.tools.reader.NetCaseMaker;
import com.sinosun.autotestmachine.tools.reader.ReadMode;
import com.sinosun.autotestmachine.tools.reader.Status;
import com.sinosun.autotestmachine.tools.utils.RunningRecorder;
import com.sinosun.autotestmachine.tools.utils.Utils;

import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;


/**
 * 任务管理器
 * @author HYW
 *
 */
public class TaskManager {
	private static TaskManager intance;			//单例模式
	private Thread taskThread;					//任务线程
	private LinkedBlockingQueue<CaseInformation> taskQueue = new LinkedBlockingQueue<>();		//任务队列
	private Handler handler;
	private int loopNum = 0;					//case 数量
	private ExecutorService threadPool = Executors.newCachedThreadPool();
	public int waitTimeSec = 60;
	
	/**
	 * 向线程池中添加线程
	 * @param t
	 */
	public void addThread(Thread t) {
		threadPool.execute(t);
	}
	
	/**
	 * 等待线程池中的所有线程运行结束
	 */
	public void startWaitToEnd() {
		if (threadPool == null) return;
		int threadCount = ((ThreadPoolExecutor)threadPool).getActiveCount();
		if (threadCount <= 0) return;
		
		threadPool.shutdown();
		try {
			threadPool.awaitTermination(30, TimeUnit.MINUTES);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		threadPool = Executors.newCachedThreadPool();
	}
	
	public int getWaitTimeSec() {
		return this.waitTimeSec;
	}

	private TaskManager() { }					//私有化初始化方法
	
	public synchronized int getLoopNumber() {				//获取当前的用例个数
		return loopNum;
	}
	
	public synchronized void setLoopNumber(int loopNum) {
		this.loopNum = loopNum;
	}
	
	/**
	 * 被移除的数据
	 * @param taskId
	 * @return 移除的数据量
	 */
	public int removeTaskById(List<String> taskIds) {
		Object[] all = taskQueue.toArray();
		List<CaseInformation> toRemove = new ArrayList<CaseInformation>();
		for (String taskId : taskIds) {
			for (Object ele : all) {
				CaseInformation tmp = (CaseInformation) ele;
				if (tmp.getTaskID().equals(taskId)) {
					toRemove.add(tmp);
				}
			}
		}
		if (taskQueue.removeAll(toRemove)) {
			return toRemove.size();
		} else {
			return 0;
		}
	}
	
	private void initThread() {					//初始化任务线程
		taskThread = new Thread() {
			public void run() {
				int i = 0;
				while(App.runInformation.getRunFlag() || (!App.runInformation.getRunFlag() && App.runInformation.getTasks().size() != 0)) {
					try {
						if (i >= getLoopNumber()) {	//读取本地文件时，超限跳出
							App.runInformation.setRunFlag(false);
							App.runInformation.setCodeByNet(false);
							break;
						}
						CaseInformation task = taskQueue.take();
						if (!App.runInformation.getRunFlag() && App.runInformation.getTasks().size() == 0) {		//没有明确指出停止的任务时，全部停止
							App.runInformation.setRunFlag(false);
							App.runInformation.setCodeByNet(true);
						} else if ((!App.runInformation.getRunFlag() && App.runInformation.getTasks().size() != 0) && 
								App.runInformation.getTasks().contains(task.getTaskID())) {		//当前运行taskId与删除的taskId相同
							App.runInformation.setRunFlag(false);
							App.runInformation.setCodeByNet(true);
							break;
						} else if ((!App.runInformation.getRunFlag() && App.runInformation.getTasks().size() != 0) && 
								!App.runInformation.getTasks().contains(task.getTaskID())) {		//被终止用例并未运行，清除队列相关数据继续运行
							App.runInformation.setRunFlag(true);
							App.runInformation.setCodeByNet(false);
							loopNum = loopNum - removeTaskById(App.runInformation.getTasks());
							NetCaseMaker.reportTaskResult(App.runInformation.getTaskId(), "1", "", "0");
							App.runInformation.setTaskId(new String(""));
							App.runInformation.clearTasks();
						}
						i++;
						Log.e("XXX", "-------------------------------> i=" + i);
						Log.e("XXX", "-------------------------------> taskID:" + task.getTaskID() + ",tag:" + task.getLastOnetTag());
						
						makeTaskTitle(task);
						CaseScheduler.getInstance().runCaseTask(task);
						makeTaskEnd(task);
						
						if (!TextUtils.isEmpty(task.getTaskID())) {		//网络任务存在 taskId
							if (task.getLastOnetTag()) {
								Message m = handler.obtainMessage();
								m.what = App.TEST_REPORT_RESULT_FLAG;
								m.obj = task.getTaskID();
								handler.sendMessage(m);
							}
						}

					} catch (InterruptedException e) {
						e.printStackTrace();
						App.runInformation.setRunFlag(false);
						App.runInformation.setCodeByNet(false);		//超限自行结束
						break;
					}
				}
				if (App.runInformation.getCodeByNet()) {		//上报结束指令的结果
					NetCaseMaker.reportTaskResult(App.runInformation.getTaskId(), "1", "", "0");
					Message m = handler.obtainMessage();
					m.what = App.TEST_REPORT_ALL_RESULT_FLAG;
					handler.sendMessage(m);
				}
				App.runInformation.clearTasks();
				if (App.caseReadMode == ReadMode.NETWORK) {
					NetCaseMaker.reportDeviceStatus(Status.IDLE);
				}
				RunningRecorder.getRunningRecorder().stopRecord();	//停止记录
				Message msg = handler.obtainMessage();
				msg.what = App.TEST_STOP_FLAG;
				handler.sendMessage(msg);
				taskQueue.clear();		//清理未完成的任务
				
			}
		};
	}
	
	//生成 case 头部，并要求打印
	private void makeTaskTitle (CaseInformation task) {
		String str = "{\n\"" + ParamKey.CASE_ID + "\":" + task.getCaseId() + ",\n\"" + ParamKey.CASE_DECRIPTION + "\":\"" + task.getCaseDecription() + "\",\n\"" + ParamKey.STEP_RESULT + "\":[";
		Element e = new Element((int)task.getCaseId());
		e.setEleStr(str);
		e.setTaskId(task.getTaskID());
		sendPrintCmd(e);
	}
	
	//生成 case 尾部，并要求打印
	private void makeTaskEnd (CaseInformation task) {
		Element e = new Element((int)task.getCaseId());
		e.setEleFlag(0);
		e.setEndFlag(true);
		e.setTaskId(task.getTaskID());
		sendPrintCmd(e);
	}
	
	//发送打印指令
	public void sendPrintCmd(Element ele) {
		Element e = new Element(ele.getIndex());
		e.setEleFlag(ele.getEleFlag());
		e.setEndFlag(ele.getEndFlag());
//		if (ele.getEndFlag()) {
			e.setTaskId(ele.getTaskId());
//		}
		Message m = handler.obtainMessage();
		m = handler.obtainMessage();
		e.setEleStr(ele.getEleStr());
		m.obj = e;
		m.what = App.TEST_RESULT;
		handler.sendMessage(m);		//case 运行结束后添加实际数据
	}

	public synchronized static TaskManager getTaskManager() {
		if (intance == null) {
			intance = new TaskManager();
		}
		return intance;
	}
	
	public void setHandler(Handler handler) {
		this.handler = handler;
	}
	
	public void startTest() {
		switch (App.caseReadMode) 
		{
		case FILE:
			loopNum = InformationReader.getInformationReader().start(App.caseReadMode);
			realStartTest();		//本地文件直接开启测试线程
			break;
		case NETWORK:
			InformationReader.getInformationReader().start(App.caseReadMode);
			break;
		default:
			break;
		}
	}
	
	public void realStartTest() {
		if (!App.runInformation.getRunFlag()) {		//处于停止状态，可以启动测试线程
			App.runInformation.setRunFlag(true);
			RunningRecorder.getRunningRecorder().initRunningRecorder(App.getInstance().getLogPath() + Utils.calendarToString(Calendar.getInstance()) + ".txt");
			initThread();
			if (App.caseReadMode == ReadMode.NETWORK) {
				loopNum = 0;
			}
			App.allInfo.clear();
			taskThread.start();
			Message m = handler.obtainMessage();
			m.what = App.TEST_START_FALG;
			handler.sendMessage(m);
		}
	}
	
	public void stopTest() {
		if (App.runInformation.getRunFlag()) {	//处于正在运行状态下，可以调用停止线程
			App.runInformation.setRunFlag(false);
		}
	}
	
	public boolean putTask(CaseInformation task) {		//添加新的任务
		return taskQueue.add(task);
	}
	
	public void setTestFileDir(String path) {			//设置测试文件的路径
		InformationReader.getInformationReader().setTestFileDir(path);
	}
}
